#define RUN_IN_CONSOLE

using System.Collections.Generic;
using System.ServiceProcess;
using System.Text;
using FscNET.NamedPipes;
using FscNET.Apm;

namespace FscNET.TraceServer
{
    static class Program
    {
        private const int BUFFER_SIZE = 4096;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
#if RUN_IN_CONSOLE
            AsyncEnumerator ae = new AsyncEnumerator();
            ae.BeginExecute(RunConsoleServer(ae), ae.EndExecute, null);
            System.Console.ReadLine();
#else

            ServiceBase[] ServicesToRun;

            // More than one user Service may run within the same process. To add
            // another service to this process, change the following line to
            // create a second service object. For example,
            //
            //   ServicesToRun = new ServiceBase[] {new Service1(), new MySecondUserService()};
            //
            ServicesToRun = new ServiceBase[] { new NamedPipeServer() };

            ServiceBase.Run(ServicesToRun);
#endif
        }

#if RUN_IN_CONSOLE
        static readonly ASCIIEncoding encoder = new ASCIIEncoding();
        private static readonly char[] traceSplitter = new char[] {'\0'};
        private static IEnumerator<int> RunConsoleServer(AsyncEnumerator ae)
        {
            byte[] buffer = new byte[BUFFER_SIZE];
            using (NamedPipeServerStream pipe = new NamedPipeServerStream(
                "CooTracePipe",
                PipeDirection.In,
                16,
                PipeTransmissionMode.Message,
                PipeOptions.WriteThrough | PipeOptions.Asynchronous
                ))
            {
                pipe.BeginWaitForConnection(ae.End(), null);
                yield return 1;

                AsyncEnumerator aeNew = new AsyncEnumerator();
                aeNew.BeginExecute(RunConsoleServer(aeNew), aeNew.EndExecute, null);

                pipe.EndWaitForConnection(ae.DequeueAsyncResult());

                while (true)
                {
                    int bytesRead;

                    pipe.BeginRead(buffer, 0, BUFFER_SIZE, ae.End(), null);
                    yield return 1;

                    try
                    {
                        bytesRead = pipe.EndRead(ae.DequeueAsyncResult());
                        if (bytesRead == 0) yield break;
                    }
                    catch
                    {
                        yield break;
                    }
                    string messages = encoder.GetString(buffer, 0, bytesRead);

                    foreach (string message in messages.Split(traceSplitter, System.StringSplitOptions.RemoveEmptyEntries))
                    {
                        System.Console.WriteLine(new string('_', 80));
                        System.Console.WriteLine(message);
                    }
                }
            }
        }
#endif
    }
}